package club.yunqiang.util;

import club.yunqiang.properties.RdsProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author YunQiang
 */
public class RdsUtils {

	private static DateFormat format = new SimpleDateFormat("yyyy-MM-DD hh:mm:ss");

	private static final String MAC_NAME = "HmacSHA1";

	private static final String ENCODING = "UTF-8";

	private static final String HTTP_METHOD = "GET";

	private static final String BASE_URL = "https://rds.aliyuncs.com/";



	private static Map<String, String> getPublicParam(String accessKeyId) {
		//按key进行比较
		Map<String, String> map = new HashMap<>();

		//加入公共参数
		map.put("Format", "json");
		map.put("Version", "2014-08-15");
		map.put("AccessKeyId", accessKeyId);
		map.put("SignatureMethod", "HMAC-SHA1");
		map.put("Timestamp", RdsUtils.getUTCTimeStr());
		map.put("SignatureVersion", "1.0");
		map.put("SignatureNonce", "69" + System.currentTimeMillis());


		return map;
	}

	public static String generateRequestUrl(String accessKeyId,String secret, Map<String, String> param) {
		// 合并参数
		Map<String, String> allParam = getPublicParam(accessKeyId);
		for (String key : param.keySet()) {
			allParam.put(key, param.get(key));
		}

		// 修改时间中的“:”
		allParam.put("Timestamp", allParam.get("Timestamp").replaceAll(":", URLEncoder.encode(":")));

		// 拼接url
		StringBuffer sb = new StringBuffer();
		String temp = HTTP_METHOD + "&" + percentEncode("/") + "&";
		sb.append(temp);
		// 参数排序、编码
		List<String> keySet = new ArrayList<>(allParam.keySet());
		Collections.sort(keySet);
		for (String key : keySet) {
			sb.append(percentEncode(key));
			sb.append(percentEncode("="));
			sb.append(percentEncode(allParam.get(key)));
			sb.append(percentEncode("&"));
		}

		String stringToSign = sb.toString();
		// 去除最后一个&
		stringToSign = stringToSign.substring(0, stringToSign.length() - 3);
		// 将加号（+）替换成%20、星号（*）替换成%2A、%7E替换回波浪号（~）
		stringToSign = stringToSign.replaceAll("\\+", "%20")
				.replaceAll("\\*", "%2A")
				.replaceAll("%7E", "~");

		// 计算签名
		String key = secret + "&";
		String sign = "";
		try {
			sign = hmacSHA1Encrypt(stringToSign, key);
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 拼接url
		// 将签名加入到请求参数中
		String requestURL = BASE_URL + "?" +  "Signature=" + sign;
		StringBuffer sbUrl = new StringBuffer();
		sbUrl.append(requestURL);
		for (String urlKey :keySet) {
			sbUrl.append("&" + urlKey + "=" + allParam.get(urlKey));
		}
		requestURL = sbUrl.toString();
		return requestURL;
	}

	/**
	 * 编码
	 *
	 * @param str
	 * @return
	 */
	private static String percentEncode(String str) {
		try {
			str = URLEncoder.encode(str, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return str;
	}

	/**
	 * HMAC-SHA1 加密
	 * @param encryptText
	 * @param encryptKey
	 * @return
	 * @throws Exception
	 */
	public static String hmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {
		byte[] data=encryptKey.getBytes(ENCODING);
		//根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
		SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
		//生成一个指定 Mac 算法 的 Mac 对象
		Mac mac = Mac.getInstance(MAC_NAME);
		//用给定密钥初始化 Mac 对象
		mac.init(secretKey);

		byte[] text = encryptText.getBytes(ENCODING);

		byte[] bytes = mac.doFinal(text);
		byte[] encode = Base64Utils.encode(bytes);
		//完成 Mac 操作
		return new String(encode);
	}

	/**
	 * 得到UTC时间，类型为字符串，格式为"yyyy-MM-dd HH:mm"<br />
	 * 如果获取失败，返回null
	 *
	 * @return
	 */
	private static String getUTCTimeStr() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		Calendar gc = GregorianCalendar.getInstance();
		//当前系统默认时区的时间：
		Calendar calendar = new GregorianCalendar();
		//美国洛杉矶时区
		TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
		//时区转换
		calendar.setTimeZone(tz);
		Date time = new Date();
		//1、取得本地时间：
		java.util.Calendar cal = java.util.Calendar.getInstance();
		//2、取得时间偏移量：
		int zoneOffset = cal.get(java.util.Calendar.ZONE_OFFSET);
		//3、取得夏令时差：
		int dstOffset = cal.get(java.util.Calendar.DST_OFFSET);
		//4、从本地时间里扣除这些差量，即可以取得UTC时间：
		cal.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));

		//之后调用cal.get(int x)或cal.getTimeInMillis()方法所取得的时间即是UTC标准时间。
		String utcStr = sdf.format(new Date(cal.getTimeInMillis())).replace(" ", "T") + "Z";
		return utcStr;
	}

}
